﻿<template>
  <div class="nav-page">
    <div class="container-card">
      <section class="card">
        <header class="card-header">
          <div class="title">{{ paper?.name || '作答记录详情' }}</div>
          <div class="ops">
            <el-button size="small" @click="goBack">返回</el-button>
          </div>
        </header>
        <div class="card-body">
          <div class="attempt-meta" v-if="attempt">
            <span>状态：{{ attempt.status === 2 ? '考试完成' : '考试中' }}</span>
            <span>开始：{{ formatDate(attempt.startTime) }}</span>
            <span>提交：{{ formatDate(attempt.submitTime) }}</span>
            <span>总分：{{ attempt.totalScore ?? 0 }} 分</span>
            <span>正确：{{ attempt.correctCount ?? 0 }} 题</span>
            <span>错误：{{ attempt.wrongCount ?? 0 }} 题</span>
            <span>用时：{{ attempt.timeSpentSeconds ?? 0 }} 秒</span>
          </div>

          <div v-loading="loading" class="question-list">
            <div v-for="(item, index) in questionItems" :key="item.id || index" class="question-card">
              <div class="question-header">
                <div class="question-info">
                  <span class="question-index">{{ index + 1 }}.</span>
                  <span class="question-stem">{{ item.question.stem }}</span>
                  <el-tag :type="typeTagType(item.question.questionType)" size="small" class="type-tag">
                    {{ typeText(item.question.questionType) }}
                  </el-tag>
                </div>
                <div class="answer-compare">
                  <span class="user-answer" :class="{ mismatch: !isCorrect(item) }">你的答案：{{ getUserAnswer(item)
                    }}</span>
                  <span class="correct-answer">正确答案：{{ getCorrectAnswer(item) }}</span>
                </div>
              </div>

              <!-- 选项展示（只读，标注历史选择与正确答案） -->
              <div class="question-options" v-if="hasOptions(item)">
                <div class="opt-list" :class="isShortOptions(item.options) ? 'opt-short' : 'opt-long'">
                  <div v-for="(opt, idx) in normalizeOptions(item.options)" :key="idx" class="opt-item"
                    :class="optionClass(item, idx)">
                    <span class="opt-index">{{ indexLabel(idx) }}</span>
                    <span class="opt-text">{{ optionText(opt) }}</span>
                  </div>
                </div>
              </div>

              <!-- 填空题答案展示 -->
              <div class="fill-answers" v-if="item?.question?.questionType === 4">
                <div class="answer-row">
                  <span class="label">你的答案：</span>
                  <span class="value" v-if="getFillAnswers(item).length">{{ getFillAnswers(item).join('，') }}</span>
                  <span class="value" v-else>未作答</span>
                </div>
                <div class="answer-row">
                  <span class="label">正确答案：</span>
                  <span class="value" v-if="getTruthFill(item).length">{{ getTruthFill(item).join('，') }}</span>
                  <span class="value" v-else>无</span>
                </div>
              </div>

              <!-- 作答判定 -->
              <div class="judge-row" v-if="hasJudge(item)">
                <el-tag :type="isCorrect(item) ? 'success' : 'danger'" size="small">
                  {{ isCorrect(item) ? '正确' : '错误' }}
                </el-tag>
                <span v-if="getJudgeDetail(item)" class="judge-detail">{{ getJudgeDetail(item) }}</span>
              </div>
            </div>

            <div v-if="questionItems.length === 0 && !loading" class="empty-state">
              暂无题目数据
            </div>
          </div>
        </div>
      </section>
    </div>
  </div>

</template>

<script setup lang="ts">
import { onMounted, ref, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getAttemptDetail, getPaperDetail } from '@/api/exam/exam'

const route = useRoute()
const router = useRouter()
const attemptId = String(route.params.id)

const loading = ref(false)
const attempt = ref<any | null>(null)
const paper = ref<any | null>(null)
const questionItems = ref<any[]>([])

// 从作答详情解析得到的映射：qid -> 选择项/填空/判断
const answerMap = ref<Record<number, any>>({})
const selectedMap = ref<Record<number, string[]>>({})
const fillMap = ref<Record<number, string[]>>({})
const boolMap = ref<Record<number, boolean | undefined>>({})
const correctMap = ref<Record<number, number>>({})
const judgeDetailMap = ref<Record<number, string>>({})

function formatDate(d: any): string {
  if (!d) return '-'
  try { return new Date(d).toLocaleString() } catch { return String(d) }
}

function typeText(t?: number) {
  return t === 1 ? '单选' : t === 2 ? '多选' : t === 3 ? '判断' : t === 4 ? '填空' : '-'
}
function typeTagType(t?: number) {
  return t === 1 ? 'success' : t === 2 ? 'warning' : t === 3 ? 'info' : t === 4 ? 'primary' : 'default'
}

function optionText(o: any): string {
  if (o == null) return ''
  if (typeof o === 'string') return o
  return o.content ?? o.text ?? o.label ?? o.value ?? (typeof o === 'object' ? JSON.stringify(o) : String(o))
}
function normalizeOptions(opts: any): any[] { return Array.isArray(opts) ? opts : [] }
function isShortOptions(opts: any): boolean {
  const arr = normalizeOptions(opts)
  if (arr.length !== 4) return false
  const threshold = 12
  return arr.every((o) => optionText(o).length <= threshold)
}
function indexLabel(idx: number): string { const map = ['A', 'B', 'C', 'D', 'E', 'F']; return map[idx] ?? String(idx + 1) }

function hasOptions(item: any): boolean {
  const t = item?.question?.questionType
  if (t === 1 || t === 2 || t === 3) {
    const opts = item?.options
    return Array.isArray(opts) && opts.length > 0
  }
  return false
}

function toBooleanKey(item: any, val: boolean | undefined): string | undefined {
  if (typeof val !== 'boolean') return undefined
  const opts = normalizeOptions(item.options)
  const truthyKeys = ['T', 'TRUE', 'Y', 'YES', '1', 'A']
  const falsyKeys = ['F', 'FALSE', 'N', 'NO', '0', 'B']
  for (const o of opts) {
    const k = String(o?.optionKey || '').toUpperCase()
    if (val && truthyKeys.includes(k)) return o.optionKey
    if (!val && falsyKeys.includes(k)) return o.optionKey
    const text = optionText(o)
    if (val && (text.includes('正确') || text.includes('是'))) return o.optionKey
    if (!val && (text.includes('错误') || text.includes('否'))) return o.optionKey
  }
  // 默认返回第一个选项键（避免无匹配时无法展示选择）
  return opts[0]?.optionKey
}

function getSelectedKeys(item: any): string[] {
  const qid = item?.question?.id
  const res = selectedMap.value[qid!] || []
  if (res.length) return res
  // 瀵瑰垽鏂鐢?bool 鏄犲皠
  const b = boolMap.value[qid!]
  const key = toBooleanKey(item, b)
  return key ? [key] : []
}

function getFillAnswers(item: any): string[] {
  const qid = item?.question?.id
  return fillMap.value[qid!] || []
}

function getTruthFill(item: any): string[] {
  const opts = normalizeOptions(item.options)
  return opts.filter((o: any) => o?.isCorrect === 1 && String(o?.optionKey || '').toLowerCase().startsWith('blank'))
            .map((o: any) => optionText(o))
}

// —— 答案展示 ——
function getCorrectAnswer(item: any): string {
  const t = item?.question?.questionType
  const opts = normalizeOptions(item.options)
  const correctOptions = opts.filter((opt: any) => opt?.isCorrect === 1)

  if (t === 4) {
    const blanks = getTruthFill(item)
    return blanks.length ? blanks.join('，') : '未设置'
  }

  if (!Array.isArray(opts) || opts.length === 0) return '未设置'

  if (t === 1) {
    return correctOptions[0]?.optionKey ?? '未设置'
  }
  if (t === 2) {
    return correctOptions.length ? correctOptions.map((opt: any) => opt.optionKey).join('，') : '未设置'
  }
  if (t === 3) {
    const key = correctOptions[0]?.optionKey
    const k = String(key || '').toUpperCase()
    const truthy = ['T', 'TRUE', 'Y', 'YES', '1', 'A']
    const falsy = ['F', 'FALSE', 'N', 'NO', '0', 'B']
    if (truthy.includes(k)) return '正确'
    if (falsy.includes(k)) return '错误'
    const text = correctOptions[0] ? optionText(correctOptions[0]) : ''
    if (text.includes('正确') || text.includes('是')) return '正确'
    if (text.includes('错误') || text.includes('否')) return '错误'
    return key ?? '未设置'
  }
  return correctOptions.length ? correctOptions.map((opt: any) => opt.optionKey).join('，') : '未设置'
}

function getUserAnswer(item: any): string {
  const t = item?.question?.questionType
  const qid = item?.question?.id
  if (t === 4) {
    const fills = getFillAnswers(item)
    return fills.length ? fills.join('，') : '未作答'
  }
  const selectedKeys = getSelectedKeys(item)
  if (!selectedKeys.length) {
    const b = boolMap.value[qid!]
    if (typeof b === 'boolean') return b ? '正确' : '错误'
    return '未作答'
  }
  if (t === 3) {
    const key = selectedKeys[0]
    const k = String(key || '').toUpperCase()
    const truthy = ['T', 'TRUE', 'Y', 'YES', '1', 'A']
    const falsy = ['F', 'FALSE', 'N', 'NO', '0', 'B']
    if (truthy.includes(k)) return '正确'
    if (falsy.includes(k)) return '错误'
    const opts = normalizeOptions(item.options)
    const opt = opts.find((o: any) => String(o?.optionKey) === key)
    const text = optionText(opt)
    if (text.includes('正确') || text.includes('是')) return '正确'
    if (text.includes('错误') || text.includes('否')) return '错误'
    return key
  }
  return selectedKeys.join('，')
}

function hasJudge(item: any): boolean {
  const qid = item?.question?.id
  return correctMap.value[qid!] != null
}
function isCorrect(item: any): boolean {
  const qid = item?.question?.id
  return !!correctMap.value[qid!]
}
function getJudgeDetail(item: any): string {
  const qid = item?.question?.id
  return judgeDetailMap.value[qid!] || ''
}

function optionClass(item: any, idx: number): Record<string, boolean> {
  const opts = normalizeOptions(item.options)
  const opt = opts[idx]
  const key = opt?.optionKey
  const truth = opt?.isCorrect === 1
  const selected = getSelectedKeys(item).includes(key)
  return {
    truth,
    selected,
    'selected-wrong': selected && !truth,
  }
}

async function loadDetail() {
  loading.value = true
  try {
    const { data } = await getAttemptDetail(attemptId)
    const body = data?.data || {}
    attempt.value = body.attempt
    const answers: any[] = Array.isArray(body.answers) ? body.answers : []
    // 构建映射
    answers.forEach((ans: any) => {
      const qid: number = ans?.questionId
      if (qid == null) return
      answerMap.value[qid] = ans
      // 选择项（兼容字符串/数组）
      const selRaw = ans?.selectedOptionsJson ?? ans?.selected_options_json
      let sel: string[] = []
      if (Array.isArray(selRaw)) sel = selRaw
      else if (typeof selRaw === 'string' && selRaw) {
        try { const parsed = JSON.parse(selRaw); if (Array.isArray(parsed)) sel = parsed } catch { }
      }
      selectedMap.value[qid] = sel
      // 填空
      const fillRaw = ans?.fillAnswersJson ?? ans?.fill_answers_json
      let fills: string[] = []
      if (Array.isArray(fillRaw)) fills = fillRaw
      else if (typeof fillRaw === 'string' && fillRaw) {
        try { const parsed = JSON.parse(fillRaw); if (Array.isArray(parsed)) fills = parsed } catch { }
      }
      fillMap.value[qid] = fills
      // 判断
      const b = ans?.booleanAnswer
      boolMap.value[qid] = typeof b === 'boolean' ? b : undefined
      // 判定结果
      correctMap.value[qid] = Number(ans?.isCorrect ?? 0)
      judgeDetailMap.value[qid] = String(ans?.judgeDetail ?? '')
    })

    // 加载试卷详情（获取题目与选项、正确答案）
    const paperId = attempt.value?.paperId
    if (!paperId) throw new Error('缺少试卷ID')
    const paperRes = await getPaperDetail(paperId)
    if (paperRes.data && paperRes.data.code === 0) {
      paper.value = paperRes.data.data.paper
      questionItems.value = paperRes.data.data.items
    } else {
      throw new Error('试卷详情返回格式错误')
    }
  } catch (e) {
    ElMessage.error('加载作答详情失败')
  } finally {
    loading.value = false
  }
}

function goBack() { router.back() }

onMounted(loadDetail)
</script>

<style scoped>
.nav-page {
  min-height: 100vh;
  width: 100%;
  box-sizing: border-box;
  background: #f5f7fb;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding-top: 20px;
  padding-bottom: 20px;
}

.container-card {
  height: 95vh;
  min-width: 900px;
  max-width: 1260px;
  margin: 0 auto;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 20px;
  box-shadow: 0 10px 24px rgba(31, 45, 61, 0.06);
}

.card {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid #eef1f7;
  padding: 14px 20px;
}

.title {
  font-size: 18px;
  font-weight: 700;
  color: #1f2937;
}

.ops {
  display: flex;
  gap: 8px;
}

.card-body {
  padding: 12px 20px;
  overflow-y: auto;
}

.attempt-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  color: #374151;
  margin-bottom: 8px;
}

.question-list {
  margin-top: 6px;
}

.question-card {
  border: 1px solid #e5e7eb;
  border-radius: 10px;
  margin-bottom: 10px;
  background: #fafafa;
  padding: 10px 12px;
}

.question-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.question-info {
  display: flex;
  align-items: center;
  gap: 8px;
}

.question-index {
  font-weight: 700;
  color: #1f2937;
}

.question-stem {
  color: #1f2937;
}

.type-tag {
  margin-left: auto;
}

.question-options {
  margin-top: 8px;
}

.opt-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}

.opt-short {
  grid-template-columns: repeat(2, 1fr);
}

.opt-long {
  grid-template-columns: 1fr;
}

.opt-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  background: #fff;
}

.opt-index {
  font-weight: 600;
  color: #374151;
}

.opt-text {
  color: #1f2937;
}

/* 标注状态 */
.opt-item.truth {
  border-color: #34d399;
  background: #ecfdf5;
}

.opt-item.selected {
  border-color: #60a5fa;
  background: #eff6ff;
}

.opt-item.selected-wrong {
  border-color: #fca5a5;
  background: #fff1f2;
}

.fill-answers {
  margin-top: 8px;
}

.answer-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 4px 0;
}

.answer-row .label {
  color: #6b7280;
}

.answer-row .value {
  color: #1f2937;
}

.judge-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 8px;
}

.judge-detail {
  color: #6b7280;
}

.empty-state {
  color: #6b7280;
  text-align: center;
  margin-top: 12px;
}

@media (max-width: 720px) {
  .container-card {
    min-width: auto;
    width: 100%;
  }
}

.answer-compare {
  display: flex;
  gap: 8px;
  align-items: center;
}

.user-answer {
  color: #374151;
}

.user-answer.mismatch {
  color: #dc2626;
  font-weight: 600;
}

.correct-answer {
  color: #065f46;
  font-size: 14px;
  font-weight: 500;
  background: #ecfdf5;
  padding: 4px 8px;
  border-radius: 6px;
  flex-shrink: 0;
}
</style>
